#include "NewGame.hh"
#include "Done.hh"
#include "XmlServerThread.hh"
#include "../World/Galaxy.hh"
#include "../World/Player.hh"
#include "../Exception.hh"

using namespace Network;
using namespace World;

u2 const NewGame::UNLIMITED = 0xffff;

struct MinInvalid {
    void operator() () {
        throw NonFatalProtocolError("init.mew_game.min_players invalid");
    }
};

struct MaxInvalid {
    void operator() () {
        throw NonFatalProtocolError("init.mew_game.max_players invalid");
    }
};

spNewGame NewGame::construct(QDomElement const& message) {
    QDomElement name = message.firstChildElement("name");
    QDomElement minElem = message.firstChildElement("min_players");
    QDomElement maxElem = message.firstChildElement("max_players");
    QDomNode nameText = name.firstChild();
    QDomNode minText = minElem.firstChild();
    QDomNode maxText = maxElem.firstChild();
    u2 min = parse_num(minElem, 2, MinInvalid());
    u2 max = parse_num(maxElem, UNLIMITED, MaxInvalid());

    if (!(name.isElement() && nameText.isText()))
        throw NonFatalProtocolError("init.new_game.name missing or invalid");

    if (min < 2)
        throw NonFatalProtocolError("init.new_game.min_players invalid");

    if (min > max)
        throw NonFatalProtocolError("init.new_game.max_players invalid");

    return spNewGame(new NewGame(nameText.toText().nodeValue(), min, max));
}

NewGame::NewGame(QString const& name, u2 minPlayers, u2 maxPlayers):
    name(name),
    minPlayers(minPlayers),
    maxPlayers(maxPlayers) {}

void NewGame::process_on_server(XmlServerThread& thread) {
    if (thread.get_state() != AUTH_OK)
        throw NonFatalProtocolError("init.new_game unexpected");

    spGalaxy galaxy;
    spPlayer player;

    try {
        spUser user = thread.get_user();
        spPlayer player;
        galaxy = Galaxy::construct(name, user, player, minPlayers, maxPlayers);
        thread.set_player(player);
        thread.set_state(GAME);
        Done done(true, "init.new_game ok");
        done.send_to(*(thread.get_socket()));
    } catch (GalaxyExistsException& ex) {
        Done done(false, "init.new_game failed already exists");
        done.send_to(*(thread.get_socket()));
    } catch (PlayerExistsException& ex) {
        galaxy->destruct();
        Done done(false, "init.new_game failed");
        done.send_to(*(thread.get_socket()));
    }
}

QDomDocument NewGame::to_xml() const {
    QDomDocument doc;
    QDomElement init = doc.createElement("init");
    QDomElement newGame = doc.createElement("new_game");
    QDomElement nameElem = doc.createElement("name");
    QDomText nameText = doc.createTextNode(name);
    doc.appendChild(init);
    init.appendChild(newGame);
    newGame.appendChild(nameElem);
    nameElem.appendChild(nameText);

    if (minPlayers <= 2) {
        QDomElement minElem = doc.createElement("min_players");
        QDomText minText = doc.createTextNode(QString::number(minPlayers));
        newGame.appendChild(minElem);
        minElem.appendChild(minText);
    }

    if (maxPlayers != UNLIMITED) {
        QDomElement maxElem = doc.createElement("max_players");
        QDomText maxText = doc.createTextNode(QString::number(maxPlayers));
        newGame.appendChild(maxElem);
        maxElem.appendChild(maxText);
    }

    return doc;
}

